Skip to content

Restrict global_stats access to platform admins#1706

Closed
riderx wants to merge 35 commits intomainfrom
riderx/fix-global-stats
Closed

Restrict global_stats access to platform admins#1706
riderx wants to merge 35 commits intomainfrom
riderx/fix-global-stats

Conversation

@riderx
Copy link
Member

@riderx riderx commented Feb 26, 2026

Summary (AI generated)

  • Added a migration that removes public access to global_stats and restricts SELECT to authenticated admins via public.is_admin(auth.uid()).
  • Updated RLS policy test expectations in supabase/tests/26_test_rls_policies.sql to match the new Allow admin users to select global_stats policy.
  • Updated RLS scenario tests in supabase/tests/27_test_rls_scenarios.sql to enforce denied access for anon and non-admin users, and allow access for test_admin.

Test plan (AI generated)

  • bun lint.
  • bun lint:backend.
  • Not yet executed: targeted database policy test suite due environment prerequisites.

Screenshots (AI generated)

  • Not applicable (backend/security-only changes).

Checklist (AI generated)

  • My code follows the code style of this project and passes lint checks.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • My change has adequate E2E test coverage.
  • I have tested my code manually, and I have provided steps how to reproduce my tests.

Summary by CodeRabbit

  • Access Control

    • Global statistics are now restricted to administrators; anonymous and non-admin authenticated users are denied access and will receive an access-denied response when attempting to view this data.
  • Tests

    • Security and access-control tests updated to verify denied access for anonymous/non-admin users and allowed access for admin users.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

Restricts read access to public.global_stats from anonymous users to admin-only via a migration; updates tests to assert that anonymous and non-admin authenticated users cannot read global_stats while admin-authenticated users can.

Changes

Cohort / File(s) Summary
Database Migration
supabase/migrations/20260227000000_restrict_global_stats_public_access.sql
Drops permissive anon SELECT policy and obsolete policies; creates a new policy permitting SELECT only for authenticated admin users; revokes SELECT from anon/authenticated roles and re-grants SELECT appropriately.
Policy Expectation Test
supabase/tests/26_test_rls_policies.sql
Updates expected policy name for public.global_stats from an anonymous-read description to the admin-only read policy name.
RLS Scenario Tests
supabase/tests/27_test_rls_scenarios.sql
Expands Test 4 into multi-step checks: verifies anonymous cannot read global_stats, authenticated non-admins see no rows, and admin-authenticated users can query global_stats; adjusts plan and assertion messages.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

💰 Rewarded

Poem

🐰 I hopped through SQL, trimmed anon's trail,

Admins now carry the access tale.
Tests patrol the meadow wide,
Non-admins wait outside the tide.
A tidy patch, a cautious hop — all safe inside my warren!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: restricting global_stats access to platform admins, which aligns with the migration and test updates.
Description check ✅ Passed The PR description follows the template structure with Summary, Test plan, Screenshots, and Checklist sections. However, the Test plan section indicates that targeted database policy tests were not executed due to environment prerequisites, which is a notable limitation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch riderx/fix-global-stats

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 66390bc97b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1,27 @@
-- =============================================================================

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Rename migration to a unique timestamp

This migration uses the 20260226000000 version prefix, but that prefix is already used by 20260226000000_org_rls_require_self_2fa_update.sql; Supabase migration ordering/history is version-based, so this collision can make one migration unapplied or non-deterministic across environments, which risks leaving global_stats access policy changes out of sync.

Useful? React with 👍 / 👎.

Comment on lines +72 to +76
throws_ok (
'SELECT COUNT(*) FROM public.global_stats',
'42501',
'permission denied',
'Authenticated non-admin users should not be able to select from global_stats'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check non-admin access with row visibility, not throws

This assertion expects authenticated non-admin reads to raise 42501, but the migration grants SELECT to authenticated and enforces admin-only visibility via RLS, which yields an empty result set rather than a permission error; as written, this test will fail even when the policy is working as intended.

Useful? React with 👍 / 👎.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@supabase/migrations/20260227000000_restrict_global_stats_public_access.sql`:
- Around line 25-27: The grant/revoke setup on table public.global_stats creates
asymmetric behavior: anon lacks SELECT and gets error 42501 while authenticated
has SELECT but is blocked by the RLS policy and therefore returns an empty
result (not an error), causing Test 4b in the RLS scenarios to fail; fix by
either adjusting the test expectation for authenticated non-admin users in the
test named Test 4b of the RLS scenarios to assert is_empty() instead of
throws_ok(42501), or change the privilege setup in the migration
(public.global_stats) to revoke SELECT from authenticated entirely and grant
SELECT only to a specific role that admins have so the test can continue to
expect a 42501 permission denied error.

In `@supabase/tests/27_test_rls_scenarios.sql`:
- Around line 67-77: The test currently sets "SET LOCAL role TO authenticated"
and calls throws_ok('SELECT COUNT(*) FROM public.global_stats', ...) expecting
error 42501, but RLS grants SELECT and returns zero rows (no error) and
auth.uid() is NULL because no JWT claims are set; update the test to assert
empty results instead of expecting an error (replace throws_ok with an
emptiness/count check such as is_empty or assert count = 0 for the query 'SELECT
COUNT(*) FROM public.global_stats') and before running the query set the JWT
claims/user context so auth.uid() is populated (e.g., set appropriate jwt.claims
or session context for a non-admin user) to mirror the intended non-admin
scenario rather than relying only on SET LOCAL role TO authenticated.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ab763b and 655ddee.

📒 Files selected for processing (3)
  • supabase/migrations/20260227000000_restrict_global_stats_public_access.sql
  • supabase/tests/26_test_rls_policies.sql
  • supabase/tests/27_test_rls_scenarios.sql

riderx added 23 commits March 2, 2026 18:06
@riderx riderx force-pushed the riderx/fix-global-stats branch from 9a79832 to 41e9db1 Compare March 3, 2026 14:51
…apgo into riderx/fix-global-stats

# Conflicts:
#	supabase/tests/27_test_rls_scenarios.sql
@riderx riderx force-pushed the riderx/fix-global-stats branch from 0a29b66 to 1b6d45a Compare March 3, 2026 14:52
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
supabase/tests/27_test_rls_scenarios.sql (1)

84-84: Tighten Test 4c comment wording for clarity.

The comment is a bit ambiguous; consider making it direct and role-focused.

✏️ Suggested wording tweak
--- Test 4c: Non-admin can be replaced with admin and still query this table
+++ Test 4c: Admin users should be able to query global_stats
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@supabase/tests/27_test_rls_scenarios.sql` at line 84, The comment for "Test
4c" is ambiguous; update the SQL comment text (the line starting with "-- Test
4c") to a clearer, role-focused sentence such as: "Test 4c: Ensure replacing a
non-admin role with an admin role still allows the admin to query this table."
Replace the existing ambiguous wording with that exact phrasing in the test
comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@supabase/tests/27_test_rls_scenarios.sql`:
- Line 84: The comment for "Test 4c" is ambiguous; update the SQL comment text
(the line starting with "-- Test 4c") to a clearer, role-focused sentence such
as: "Test 4c: Ensure replacing a non-admin role with an admin role still allows
the admin to query this table." Replace the existing ambiguous wording with that
exact phrasing in the test comment.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 655ddee and 2f066a5.

📒 Files selected for processing (1)
  • supabase/tests/27_test_rls_scenarios.sql

@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 3, 2026

@riderx riderx closed this Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant